home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr05 / xnot12a.zip / LINE.C < prev    next >
C/C++ Source or Header  |  1993-05-20  |  19KB  |  801 lines

  1. #include "jam.h"
  2. #include"stdlib.h"
  3. #include "def.h"
  4. #include "keyname.h"
  5. /*
  6.  *        Text line handling.
  7.  * The functions in this file
  8.  * are a general set of line management
  9.  * utilities. They are the only routines that
  10.  * touch the text. They also touch the buffer
  11.  * and window structures, to make sure that the
  12.  * necessary updating gets done. There are routines
  13.  * in this file that handle the kill buffer too.
  14.  * It isn't here for any good reason.
  15.  *
  16.  * Note that this code only updates the dot and
  17.  * mark values in the window list. Since all the code
  18.  * acts on the current window, the buffer that we
  19.  * are editing must be being displayed, which means
  20.  * that "b_nwnd" is non zero, which means that the
  21.  * dot and mark values in the buffer headers are
  22.  * nonsense.
  23.  */
  24.   
  25. #ifndef NBLOCK
  26. # define NBLOCK    16            /* Line block chunk size    */
  27. #endif
  28.  
  29. #ifndef KBLOCK
  30. # define KBLOCK    256            /* Kill buffer block size.    */
  31. #endif
  32.  
  33. static char HUGE *kbufp    = NULL;            /* Kill buffer data.        */
  34. static RSIZE    kused    = 0;        /* # of bytes used in KB.    */
  35. static RSIZE    ksize    = 0;        /* # of bytes allocated in KB.    */
  36. static RSIZE    kstart    = 0;        /* # of first used byte in KB.    */
  37.  
  38. RSIZE return_kused()
  39. {
  40.   return(kused - kstart);
  41. }
  42.  
  43. /*
  44.  * This routine allocates a block of memory large enough to hold a LINE
  45.  * containing "used" characters. The block is rounded up to whatever
  46.  * needs to be allocated. (use lallocx for lines likely to grow.)
  47.  * Return a pointer to the new block, or NULL if there isn't
  48.  * any memory left. Print a message in the message line if no space.
  49.  */
  50. LINE *lalloc(used) 
  51. register int used; 
  52. {
  53.   register LINE    *lp;
  54.   register int    size;
  55.   
  56.   size = used + sizeof(LINE);
  57.  
  58. #ifdef MALLOCROUND
  59.   MALLOCROUND(size);    /* round up to a size optimal to malloc */
  60. #endif
  61.  
  62.   if((lp = (LINE *)calloc(1, (unsigned)size)) == NULL) 
  63.     {
  64.       ewprintf(Nobytes, size);
  65.       return (LINE *)NULL;
  66.     }
  67.  
  68.   lp->l_size = size - sizeof(LINE);
  69.   lp->l_used = used;
  70.   return lp;
  71. }
  72.  
  73. /*
  74.  * Like lalloc, only round amount desired up because this line will
  75.  * probably grow.  We always make room for at least one more char.
  76.  * (thus making 0 not a special case anymore.)
  77.  */
  78. LINE *lallocx(used)
  79. int used;
  80. {
  81.   register int size;
  82.   register LINE *lp;
  83.   
  84.   size = (NBLOCK+used) & ~(NBLOCK-1);
  85.   if((lp = lalloc(size)) != NULL) 
  86.     lp->l_used = used;
  87.   return lp;
  88. }
  89.  
  90. /*
  91.  * Delete line "lp". Fix all of the
  92.  * links that might point at it (they are
  93.  * moved to offset 0 of the next line.
  94.  * Unlink the line from whatever buffer it
  95.  * might be in. Release the memory. The
  96.  * buffers are updated too; the magic conditions
  97.  * described in the above comments don't hold
  98.  * here.
  99.  */
  100. VOID lfree(lp) 
  101. register LINE *lp; 
  102. {
  103.   register BUFFER *bp;
  104.   register EWINDOW *wp;
  105.   
  106.   for(wp = wheadp; wp != NULL; wp = wp->w_wndp) 
  107.     {
  108.       if (wp->w_linep == lp)
  109.     wp->w_linep = lforw(lp);
  110.       if (wp->w_dotp    == lp) 
  111.     {
  112.       wp->w_dotp  = lforw(lp);
  113.       wp->w_doto  = 0;
  114.     }
  115.       if (wp->w_markp == lp) 
  116.     {
  117.       wp->w_markp = lforw(lp);
  118.       wp->w_marko = 0;
  119.     }
  120.     }
  121.  
  122.   for(bp = bheadp; bp != NULL; bp = bp->b_bufp) 
  123.     {
  124.       if (bp->b_nwnd == 0) 
  125.     {
  126.       if (bp->b_dotp == lp) 
  127.         {
  128.           bp->b_dotp = lforw(lp);
  129.           bp->b_doto = 0;
  130.         }
  131.       if (bp->b_markp == lp) 
  132.         {
  133.           bp->b_markp = lforw(lp);
  134.           bp->b_marko = 0;
  135.         }
  136.     }
  137.     }
  138.   lkill(lp);
  139. }
  140. void lkill(lp)
  141. LINE *lp;
  142. {
  143.   if (!lp)
  144.     return;
  145.  
  146.   if (lp->l_bp)
  147.     lp->l_bp->l_fp = lp->l_fp;
  148.   if (lp->l_fp)
  149.     lp->l_fp->l_bp = lp->l_bp;
  150.   free((char *) lp);
  151. }
  152. /*
  153.  * This routine gets called when
  154.  * a character is changed in place in the
  155.  * current buffer. It updates all of the required
  156.  * flags in the buffer and window system. The flag
  157.  * used is passed as an argument; if the buffer is being
  158.  * displayed in more than 1 window we change EDIT to
  159.  * HARD. Set MODE if the mode line needs to be
  160.  * updated (the "*" has to be set).
  161.  *
  162.  * NOTE special calls to changelineflag for marking the
  163.  * actual lines changed due to edit, etc.  Not easy to
  164.  * combine the functions. (JAM)
  165.  *
  166.  */
  167. VOID lchange(flag) 
  168. register int flag; 
  169. {
  170.   register EWINDOW *wp;
  171.   
  172.   if ((curbp->b_flag&BFCHG) == 0)     /* First change, so    */
  173.     {
  174.       curbp->b_flag |= BFCHG;
  175.       thisflag |= CFNEWC;
  176.     }
  177.  
  178.   curbp->b_flag |= BFINC;                 /* needs incremental */
  179.   flag |= WFMODE;                  /* update mode lines.    */
  180.  
  181.   for(wp = wheadp; wp != NULL; wp = wp->w_wndp) 
  182.     {
  183.       if (wp->w_bufp == curbp) 
  184.     {
  185.       wp->w_flag |= flag;
  186.       if (wp != curwp) 
  187.         wp->w_flag |= WFHARD;
  188.     }
  189.     }
  190. }
  191.  
  192. /*
  193.  * Insert "n" copies of the character "c"
  194.  * at the current location of dot. In the easy case
  195.  * all that happens is the text is stored in the line.
  196.  * In the hard case, the line has to be reallocated.
  197.  * When the window list is updated, take special
  198.  * care; I screwed it up once. You always update dot
  199.  * in the current window. You update mark, and a
  200.  * dot in another window, if it is greater than
  201.  * the place where you did the insert. Return TRUE
  202.  * if all is well, and FALSE on errors.
  203.  */
  204. linsert(n, c)
  205. int n, c;
  206. {
  207.   register char    *cp1;
  208.   register char    *cp2;
  209.   register LINE    *lp1;
  210.   LINE        *lp2;
  211.   LINE        *lp3;
  212.   register int    doto;
  213.   register RSIZE    i;
  214.   EWINDOW        *wp;
  215.   
  216.   if (curbp->b_flag & BFVIEW)
  217.     {
  218.       ttbeep();
  219.       return FALSE;
  220.     }
  221.  
  222.   lchange(WFEDIT);
  223.   lp1 = curwp->w_dotp;        /* Current line        */
  224.   if (lp1 == curbp->b_linep)    /* At the end: special    */
  225.     {                           /* now should only happen in empty buffer */
  226.       if (curwp->w_doto != 0) 
  227.     {
  228.       ewprintf("Bug!: linsert");
  229.       return FALSE;
  230.     }
  231.       
  232.       if ((lp2=lallocx(n)) == NULL) /* Allocate new line */
  233.     return FALSE;
  234.       changelineflag(lp2, TRUE);
  235.  
  236.       lp3 = lback(lp1);        /* Previous line    */
  237.       lforw(lp3) = lp2;        /* Link in        */
  238.       lforw(lp2) = lp1;
  239.       lback(lp1) = lp2;
  240.       lback(lp2) = lp3;
  241.  
  242.       for (i=0; i<n; ++i)
  243.     lp2->l_text[i] = (char)c;
  244.  
  245.       for(wp = wheadp; wp != NULL; wp = wp->w_wndp) 
  246.     {
  247.       if (wp->w_linep == lp1)
  248.         wp->w_linep = lp2;
  249.       if (wp->w_dotp == lp1)
  250.         wp->w_dotp = lp2;
  251.       if (wp->w_markp == lp1)
  252.         wp->w_markp = lp2;
  253.     }
  254.       /*NOSTRICT*/
  255.       curwp->w_doto = n;
  256.       return TRUE;
  257.     }
  258.   doto = curwp->w_doto;            /* Save for later.    */
  259.   /*NOSTRICT (2) */
  260.  
  261.   if (lp1->l_used+n > lp1->l_size)     /* Hard: reallocate    */
  262.     {
  263.       if ((lp2=lallocx(lp1->l_used+n)) == NULL)
  264.     return FALSE;
  265.       changelineflag(lp2, TRUE);
  266.       cp1 = &lp1->l_text[0];
  267.       cp2 = &lp2->l_text[0];
  268.       while (cp1 != &lp1->l_text[doto])
  269.     *cp2++ = *cp1++;
  270.       /*NOSTRICT*/
  271.       cp2 += n;
  272.       while (cp1 != &lp1->l_text[lp1->l_used])
  273.     *cp2++ = *cp1++;
  274.       lp1->l_bp->l_fp = lp2;
  275.       lp2->l_fp = lp1->l_fp;
  276.       lp1->l_fp->l_bp = lp2;
  277.       lp2->l_bp = lp1->l_bp;
  278.       free((char *) lp1);
  279.     } 
  280.   else 
  281.     {                /* Easy: in place    */
  282.       lp2 = lp1;        /* Pretend new line    */
  283.       changelineflag(lp2, TRUE);
  284.       /*NOSTRICT*/
  285.       lp2->l_used += n;
  286.       cp2 = &lp1->l_text[lp1->l_used];
  287.       
  288.       cp1 = cp2-n;
  289.       while (cp1 != &lp1->l_text[doto])
  290.     *--cp2 = *--cp1;
  291.     }
  292.  
  293.   for (i=0; i<n; ++i)            /* Add the characters    */
  294.     lputc(lp2, doto + i, (char)c);
  295.   
  296.   for(wp = wheadp; wp != NULL; wp = wp->w_wndp) 
  297.     {
  298.       if (wp->w_linep == lp1)
  299.     wp->w_linep = lp2;
  300.       if (wp->w_dotp == lp1) 
  301.     {
  302.       wp->w_dotp = lp2;
  303.       if (wp==curwp || wp->w_doto>doto)
  304.         /*NOSTRICT*/
  305.         wp->w_doto += n;
  306.     }
  307.       if (wp->w_markp == lp1) 
  308.     {
  309.       wp->w_markp = lp2;
  310.       if (wp->w_marko > doto)
  311.         /*NOSTRICT*/
  312.         wp->w_marko += n;
  313.     }
  314.     }
  315.   return TRUE;
  316. }
  317.  
  318. /*
  319.  * Insert a newline into the buffer
  320.  * at the current location of dot in the current
  321.  * window.  The funny ass-backwards way is no longer used.
  322.  */
  323. lnewline()
  324. {
  325.   register LINE    *lp1;
  326.   register LINE    *lp2;
  327.   register int    doto;
  328.   register int    nlen;
  329.   EWINDOW        *wp;
  330.   
  331.   if (curbp->b_flag & BFVIEW)
  332.     {
  333.       ttbeep();
  334.       return FALSE;
  335.     }
  336.  
  337.   lchange(WFHARD);
  338.   lp1  = curwp->w_dotp;            /* Get the address and    */
  339.   doto = curwp->w_doto;            /* offset of "."    */
  340.   if(doto == 0)             /* avoid unneeded copying */
  341.     {
  342.       if((lp2 = lallocx(0)) == NULL)    /* new first part    */
  343.     return FALSE;
  344.       changelineflag(lp2, TRUE);
  345.       lp2->l_bp = lp1->l_bp;
  346.       lp1->l_bp->l_fp = lp2;
  347.       lp2->l_fp = lp1;
  348.       lp1->l_bp = lp2;
  349.       for(wp = wheadp; wp!=NULL; wp = wp->w_wndp)
  350.     if(wp->w_linep == lp1) 
  351.           wp->w_linep = lp2;
  352.       return TRUE;
  353.     }
  354.   nlen = llength(lp1) - doto;        /* length of new part    */
  355.   if((lp2=lallocx(nlen)) == NULL)    /* New second half line */
  356.     return FALSE;
  357.   changelineflag(lp2, TRUE);
  358.   if(nlen!=0) 
  359.     bcopy(&lp1->l_text[doto], &lp2->l_text[0], nlen);
  360.   if (lp1->l_used != doto)
  361.     changelineflag(lp1, TRUE);
  362.   lp1->l_used = doto;
  363.   lp2->l_bp = lp1;
  364.   lp2->l_fp = lp1->l_fp;
  365.   lp1->l_fp = lp2;
  366.   lp2->l_fp->l_bp = lp2;
  367.  
  368.   for(wp = wheadp; wp != NULL; wp = wp->w_wndp)  /* Windows    */
  369.     {
  370.       if (wp->w_dotp == lp1 && wp->w_doto >= doto) 
  371.     {
  372.       wp->w_dotp = lp2;
  373.       wp->w_doto -= doto;
  374.     }
  375.       if (wp->w_markp == lp1 && wp->w_marko >= doto) 
  376.     {
  377.       wp->w_markp = lp2;
  378.       wp->w_marko -= doto;
  379.     }
  380.     }
  381.   return TRUE;
  382. }
  383.  
  384. /*
  385.  * This function deletes "n" bytes,
  386.  * starting at dot. It understands how do deal
  387.  * with end of lines, etc. It returns TRUE if all
  388.  * of the characters were deleted, and FALSE if
  389.  * they were not (because dot ran into the end of
  390.  * the buffer. The "kflag" indicates either no insertion,
  391.  * or direction of insertion into the kill buffer.
  392.  */
  393. ldelete(n, kflag) 
  394. RSIZE n; 
  395. int kflag;
  396. {
  397.   register char    *cp1;
  398.   register char    *cp2;
  399.   register LINE    *dotp;
  400.   register int    doto;
  401.   register RSIZE chunk;
  402.   EWINDOW *wp;
  403.   
  404.   if (curbp->b_flag & BFVIEW)
  405.     {
  406.       ttbeep();
  407.       return FALSE;
  408.     }
  409.  
  410.   /*
  411.    * HACK - doesn't matter, and fixes back-over-nl bug for empty
  412.    *    kill buffers.
  413.    */
  414.   if (kused == kstart) 
  415.     kflag = KFORW;
  416.   
  417.   while (n != 0) 
  418.     {
  419.       dotp = curwp->w_dotp;
  420.       doto = curwp->w_doto;
  421.       if (dotp == curbp->b_linep)    /* Hit end of buffer.    */
  422.     return FALSE;
  423.       chunk = dotp->l_used-doto;    /* Size of chunk.    */
  424.       if (chunk > n)
  425.     chunk = n;
  426.       if (chunk == 0)         /* End of line, merge.    */
  427.     {
  428.       if(dotp == lback(curbp->b_linep))
  429.         return FALSE;    /* End of buffer.    */
  430.       lchange(WFHARD);
  431.       if (ldelnewline() == FALSE
  432.           || (kflag!=KNONE && kinsert('\n', kflag)==FALSE))
  433.         return FALSE;
  434.       --n;
  435.       continue;
  436.     }
  437.       lchange(WFEDIT);
  438.       cp1 = &dotp->l_text[doto];    /* Scrunch text.    */
  439.       cp2 = cp1 + chunk;
  440.       if (kflag == KFORW) 
  441.     {
  442.       while (ksize - kused < chunk)
  443.         if (kgrow(FALSE) == FALSE) 
  444.               return FALSE;
  445.       bcopy(cp1, &(kbufp[kused]), (size_t) chunk);
  446.       kused += chunk;
  447.     } 
  448.       else if (kflag == KBACK) 
  449.     {
  450.       while (kstart < chunk)
  451.         if (kgrow(TRUE) == FALSE) 
  452.         return FALSE;
  453.       bcopy(cp1, &(kbufp[kstart-chunk]), (size_t) chunk);
  454.       kstart -= chunk;
  455.     } 
  456.       else if (kflag != KNONE) 
  457.     panic("broken ldelete call");
  458.       while (cp2 != &dotp->l_text[dotp->l_used])
  459.     *cp1++ = *cp2++;
  460.       dotp->l_used -= (int)chunk;
  461.       changelineflag(dotp, TRUE);
  462.       for(wp = wheadp; wp != NULL; wp = wp->w_wndp) 
  463.     {
  464.       if (wp->w_dotp==dotp && wp->w_doto>=doto) 
  465.         {
  466.           /*NOSTRICT*/
  467.           wp->w_doto -= (short)chunk;
  468.           if (wp->w_doto < doto)
  469.         wp->w_doto = doto;
  470.         }
  471.       if (wp->w_markp==dotp && wp->w_marko>=doto) 
  472.         {
  473.           /*NOSTRICT*/
  474.           wp->w_marko -= (short)chunk;
  475.           if (wp->w_marko < doto)
  476.         wp->w_marko = doto;
  477.         }
  478.     }
  479.       n -= chunk;
  480.     }
  481.   return TRUE;
  482. }
  483.  
  484. /*
  485.  * Delete a newline. Join the current line
  486.  * with the next line. If the next line is the magic
  487.  * header line always return TRUE; merging the last line
  488.  * with the header line can be thought of as always being a
  489.  * successful operation, even if nothing is done, and this makes
  490.  * the kill buffer work "right". Easy cases can be done by
  491.  * shuffling data around. Hard cases require that lines be moved
  492.  * about in memory. Return FALSE on error and TRUE if all
  493.  * looks ok.
  494.  */
  495. ldelnewline() 
  496. {
  497.   register LINE    *lp1;
  498.   register LINE    *lp2;
  499.   register EWINDOW *wp;
  500.   LINE        *lp3;
  501.   
  502.   if (curbp->b_flag & BFVIEW)
  503.     {
  504.       ttbeep();
  505.       return FALSE;
  506.     }
  507.  
  508.   lp1 = curwp->w_dotp;
  509.   lp2 = lforw(lp1);
  510.   if (lp2 == curbp->b_linep)        /* At the buffer end.    */
  511.     return TRUE;
  512.  
  513.   /* Case of current line has room to just add stuff
  514.   * to the end.
  515.   */
  516.   if (lp2->l_used <= lp1->l_size - lp1->l_used) 
  517.     {
  518.       changelineflag(lp1, TRUE);
  519.       bcopy(&lp2->l_text[0], &lp1->l_text[lp1->l_used], (size_t)lp2->l_used);
  520.       for(wp = wheadp; wp != NULL; wp = wp->w_wndp) 
  521.     {
  522.       if (wp->w_linep == lp2)
  523.         wp->w_linep = lp1;
  524.       if (wp->w_dotp == lp2) 
  525.         {
  526.           wp->w_dotp  = lp1;
  527.           wp->w_doto += lp1->l_used;
  528.         }
  529.       if (wp->w_markp == lp2) 
  530.         {
  531.           wp->w_markp  = lp1;
  532.           wp->w_marko += lp1->l_used;
  533.         }
  534.     }
  535.       lp1->l_used += lp2->l_used;
  536.       lp1->l_fp = lp2->l_fp;
  537.       lp2->l_fp->l_bp = lp1;
  538.       free((char *) lp2);
  539.       return TRUE;
  540.     }
  541.  
  542.   if ((lp3=lalloc(lp1->l_used + lp2->l_used)) == NULL)
  543.     return FALSE;
  544.  
  545.   bcopy(&lp1->l_text[0], &lp3->l_text[0], (size_t)lp1->l_used);
  546.   bcopy(&lp2->l_text[0], &lp3->l_text[lp1->l_used], (size_t)lp2->l_used);
  547.  
  548.   if ((lp1->l_used >= 1) && (lp2->l_used >= 1))
  549.     changelineflag(lp3, TRUE);    /* non-empty lines joined */
  550.  
  551.   lp1->l_bp->l_fp = lp3;
  552.   lp3->l_fp = lp2->l_fp;
  553.   lp2->l_fp->l_bp = lp3;
  554.   lp3->l_bp = lp1->l_bp;
  555.   for(wp = wheadp; wp != NULL; wp = wp->w_wndp) 
  556.     {
  557.       if (wp->w_linep==lp1 || wp->w_linep==lp2)
  558.     wp->w_linep = lp3;
  559.       if (wp->w_dotp == lp1)
  560.     wp->w_dotp  = lp3;
  561.       else if (wp->w_dotp == lp2) 
  562.     {
  563.       wp->w_dotp  = lp3;
  564.       wp->w_doto += lp1->l_used;
  565.     }
  566.       if (wp->w_markp == lp1)
  567.     wp->w_markp  = lp3;
  568.       else if (wp->w_markp == lp2) 
  569.     {
  570.       wp->w_markp  = lp3;
  571.       wp->w_marko += lp1->l_used;
  572.     }
  573.     }
  574.   free((char *) lp1);
  575.   free((char *) lp2);
  576.   return TRUE;
  577. }
  578.  
  579. /*
  580.  * Replace plen characters before dot with argument string.
  581.  * Control-J characters in st are interpreted as newlines.
  582.  * There is a casehack disable flag (normally it likes to match
  583.  * case of replacement to what was there).
  584.  */
  585. lreplace(plen, st, f)
  586. register RSIZE    plen;            /* length to remove        */
  587. char        *st;            /* replacement string        */
  588. int        f;            /* case hack disable        */
  589. {
  590.   register RSIZE rlen;        /* replacement length        */
  591.   register int    rtype;        /* capitalization        */
  592.   register int    c;        /* used for random characters    */
  593.   register int    doto;        /* offset into line        */
  594.   
  595.   if (curbp->b_flag & BFVIEW)
  596.     {
  597.       ttbeep();
  598.       return FALSE;
  599.     }
  600.  
  601.   /*
  602.    * Find the capitalization of the word that was found.
  603.    * f says use exact case of replacement string (same thing that
  604.    * happens with lowercase found), so bypass check.
  605.    */
  606.   /*NOSTRICT*/
  607.   (VOID) backchar(FFARG | FFRAND, (int) plen);
  608.   rtype = _L;
  609.   c = lgetc(curwp->w_dotp, curwp->w_doto);
  610.   if (ISUPPER(c)!=FALSE  &&  f==FALSE) 
  611.     {
  612.       rtype = _U|_L;
  613.       if (curwp->w_doto+1 < llength(curwp->w_dotp)) 
  614.     {
  615.       c = lgetc(curwp->w_dotp, curwp->w_doto+1);
  616.       if (ISUPPER(c) != FALSE) 
  617.         {
  618.           rtype = _U;
  619.         }
  620.     }
  621.     }
  622.   
  623.   /*
  624.    * make the string lengths match (either pad the line
  625.    * so that it will fit, or scrunch out the excess).
  626.    * be careful with dot's offset.
  627.    */
  628.   rlen = strlen(st);
  629.   doto = curwp->w_doto;
  630.   if (plen > rlen)
  631.     (VOID) ldelete((RSIZE) (plen-rlen), KNONE);
  632.   else if (plen < rlen) 
  633.     {
  634.       if (linsert((int)(rlen-plen), ' ') == FALSE)
  635.     return FALSE;
  636.     }
  637.   curwp->w_doto = doto;
  638.   
  639.   /*
  640.    * do the replacement:    If was capital, then place first
  641.    * char as if upper, and subsequent chars as if lower.
  642.    * If inserting upper, check replacement for case.
  643.    */
  644.   while ((c = CHARMASK(*st++)) != '\0') 
  645.     {
  646.       if ((rtype&_U)!=0  &&  ISLOWER(c)!=0)
  647.     c = TOUPPER(c);
  648.       if (rtype == (_U|_L))
  649.     rtype = _L;
  650.       if (c == CCHR('J')) 
  651.         {
  652.       if (curwp->w_doto == llength(curwp->w_dotp))
  653.         (VOID) forwchar(FFRAND, 1);
  654.           else 
  655.         {
  656.           if (ldelete((RSIZE) 1, KNONE) != FALSE)
  657.             (VOID) lnewline();
  658.         }
  659.         } 
  660.       else if (curwp->w_dotp == curbp->b_linep) 
  661.     {
  662.       (VOID) linsert(1, c);
  663.     } 
  664.       else if (curwp->w_doto == llength(curwp->w_dotp)) 
  665.     {
  666.       if (ldelete((RSIZE) 1, KNONE) != FALSE)
  667.         (VOID) linsert(1, c);
  668.     } 
  669.       else
  670.         {
  671.           changelineflag(curwp->w_dotp, TRUE);
  672.       lputc(curwp->w_dotp, curwp->w_doto++, (char)c);
  673.         }
  674.     }
  675.   lchange(WFHARD);
  676.   return (TRUE);
  677. }
  678.  
  679. /*
  680.  * Delete all of the text
  681.  * saved in the kill buffer. Called by commands
  682.  * when a new kill context is being created. The kill
  683.  * buffer array is released, just in case the buffer has
  684.  * grown to immense size. No errors.
  685.  */
  686. VOID kdelete() 
  687. {
  688.   if (kbufp != NULL) 
  689.     {
  690.       ewprintf(garbage);
  691.       free((char *) kbufp);
  692.       kbufp = NULL;
  693.       kstart = kused = ksize = 0;
  694.     }
  695. }
  696.  
  697. /*
  698.  * Insert a character to the kill buffer,
  699.  * enlarging the buffer if there isn't any room. Always
  700.  * grow the buffer in chunks, on the assumption that if you
  701.  * put something in the kill buffer you are going to put
  702.  * more stuff there too later. Return TRUE if all is
  703.  * well, and FALSE on errors. Print a message on
  704.  * errors. Dir says whether to put it at back or front.
  705.  */
  706. kinsert(c, dir) 
  707. int c, dir;
  708. {  
  709.   if (kused == ksize && dir == KFORW && kgrow(FALSE) == FALSE)
  710.     return FALSE;
  711.   if (kstart == 0 && dir == KBACK && kgrow(TRUE) == FALSE)
  712.     return FALSE;
  713.   if (dir == KFORW) 
  714.     kbufp[kused++] = (char)c;
  715.   else if (dir == KBACK) 
  716.     kbufp[--kstart] = (char)c;
  717.   else 
  718.     panic("Broken kinsert call");        /* Oh shit! */
  719.   return (TRUE);
  720. }
  721.  
  722. /*
  723.  * kgrow - just get more kill buffer for the callee. back is true if
  724.  * we are trying to get space at the beginning of the kill buffer.
  725.  */
  726. kgrow(back) 
  727. int back;
  728. {
  729.   register RSIZE nstart;
  730.   register char    *nbufp;
  731.   
  732.   if ((unsigned)(ksize+KBLOCK) <= (unsigned)ksize) 
  733.     {
  734.       /* probably 16 bit unsigned; one of these days I 
  735.       * will fix this to be a linked-list of lines (JAM)
  736.       */
  737.       ewprintf("Kill buffer size at maximum.");
  738.       return FALSE;
  739.     }
  740.   if ((nbufp=malloc((unsigned)(ksize+KBLOCK))) == NULL) 
  741.     {
  742.       ewprintf(Nobytes, (long)(ksize+KBLOCK));
  743.       return FALSE;
  744.     }
  745.   nstart = (back == TRUE) ? (kstart + KBLOCK) : (KBLOCK / 4) ;
  746.  
  747.   bcopy(&(kbufp[kstart]), &(nbufp[nstart]), (size_t)(kused-kstart));
  748.  
  749.   if (kbufp != NULL)
  750.     free((char *) kbufp);
  751.   kbufp = nbufp;
  752.   ksize += KBLOCK;
  753.   kused = kused - kstart + nstart;
  754.   kstart = nstart;
  755.   return TRUE;
  756. }
  757.  
  758. char *killbufstart()
  759. {
  760.  return(&kbufp[kstart]);
  761. }
  762. /*
  763.  * This function gets characters from
  764.  * the kill buffer. If the character index "n" is
  765.  * off the end, it returns "-1". This lets the caller
  766.  * just scan along until it gets a "-1" back.
  767.  */
  768. kremove(n) 
  769. RSIZE n;
  770. {
  771.   if (n < 0 || n + kstart >= kused)
  772.     return -1;
  773.   return CHARMASK(kbufp[n + kstart]);
  774. }
  775. /* insert a line at dotp of curbp
  776. */
  777. int lineinsert(s, nl)
  778. char *s;
  779. BOOL nl;
  780. {
  781.   while (*s)
  782.     if (!linsert(1, *s++))
  783.       return(FALSE);
  784.   if (nl)
  785.     return(lnewline());
  786.   else
  787.     return (TRUE);
  788. }
  789.  
  790. #ifdef DEBUG
  791. void changelineflag(lp, flag)
  792. LINE *lp;
  793. BOOL flag;
  794. {
  795.   if (flag)
  796.     lp->l_flag |= LFCHANGE;
  797.   else
  798.     lp->l_flag &= ~LFCHANGE;
  799. }
  800. #endif    
  801.